package emulator.shell.GUI.profiling;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.swing.table.AbstractTableModel;

import emulator.hardware.HwWord;
import emulator.hardware.debug.profiling.CodeSegment;

@SuppressWarnings("serial")
public class CallTableModel extends AbstractTableModel
{
	private static String[] columns = { "Total cycles", "Cycles", "Hit count", "Avg. Cycles", "Address", "Label" };
	private List<CallTableData> data = new ArrayList<CallTableData>();
	private Map<Integer, CallTableData> addressMap = new HashMap<Integer, CallTableData>();

	@Override
	public String getColumnName(int column)
	{
		return columns[column];
	}

	@Override
	public int getRowCount()
	{
		return data.size();
	}

	@Override
	public int getColumnCount()
	{
		return columns.length;
	}

	@Override
	public Object getValueAt(int rowIndex, int columnIndex)
	{
		switch (columnIndex)
		{
		case 0: return data.get(rowIndex).getSumTotalTicks();
		case 1: return data.get(rowIndex).getSumTicks();
		case 2: return data.get(rowIndex).getHitCount();
		case 3: return (data.get(rowIndex).getHitCount() > 0 ? data.get(rowIndex).getSumTicks()/data.get(rowIndex).getHitCount() : 0);
		case 4: return "$"+new HwWord(data.get(rowIndex).getEnterAddress());
		case 5: return data.get(rowIndex).getLabel();
		}
		return null;
	}

	@Override
	public Class<?> getColumnClass(int columnIndex)
	{
		switch (columnIndex)
		{
		case 0: return Integer.class;
		case 1: return Integer.class;
		case 2: return Integer.class;
		case 3: return Integer.class;
		case 4: return String.class;
		case 5: return String.class;
		}
		return super.getColumnClass(columnIndex);
	}

	public void prepareCodeSegment(CodeSegment codeSegment, String label)
	{
		CallTableData element = new CallTableData();
		element.setEnterAddress(codeSegment.getEnterAddress());
		element.setLabel(label);
		element.setExitAddresses(new LinkedList<Integer>(codeSegment.getExitAddresses()));
		element.setHitCount(codeSegment.getCallCount());
		element.setSumTotalTicks(codeSegment.getSumTicks());
		element.setSumTicks(codeSegment.getSumTicks() - codeSegment.getSubTicks());
		addressMap.put(element.getEnterAddress(), element);
	}

	public void processCodeSegment(CodeSegment codeSegment)
	{
		CallTableData element = addressMap.get(codeSegment.getEnterAddress());
		for (CodeSegment calledSegment : codeSegment.getChildren())
		{
			CallTableData child = addressMap.get(calledSegment.getEnterAddress());
			child.getParents().add(element);
			element.getChildren().add(child);
		}
		data.add(element);
	}

	public int getAddressAtRow(int rowIndex)
	{
		return data.get(rowIndex).getEnterAddress();
	}
	
	public void postProcess()
	{
		Collections.sort(data);
	}
}

